﻿<?

/*
 * This file is part of the SmartSelect package.
 * (c) 2007 Endeveit <endeveit@gmail.com>
 * (c) 2007 Alexander Zinchuk <alx@vingrad.ru>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

/**
 * IllegalStateException is thrown while attempting to create new SmartSelect implementation instance
 *
 * @package  SmartSelect
 */
class IllegalStateException extends Exception {}

/**
 * CloneNotSupportedException is thrown while attempting to clone SmartSelect instance
 *
 * @package  SmartSelect
 */
class CloneNotSupportedException extends Exception {}

/**
 * SmartSelect manages new SmartSelect listboxes
 *
 * @package  SmartSelect
 * @author   Endeveit <endeveit@gmail.com>
 * @author   Alexander Zinchuk <alx@vingrad.ru>
 */
class SmartSelect
{
    /**
     * The instance of SmartSelect object
     *
     * @var  $instance
     */
    private static $instance = null;

    /**
     * Returns self instance
     *
     * @return  SmartSelect
     */
    public static function getInstance()
    {
        if (!self::$instance instanceof self || self::$instance === null) {
            self::$instance = new self();
        }
        return self::$instance;
    }

    /**
     * Return new SmartSelect listbox
     *
     * @param   string            $xml_file      Path to xml-file with data, or JSON-string
     * @param   string            $attributes    List attributes
     * @throws  RuntimeException
     * @return  string
     */
    public function newSmartSelect($xml_file = 'default', $attributes = null)
    {
        if(is_array($tmp = json_decode($xml_file, 1))) {
            $xml = simplexml_load_string('<fwc:select id="sselect" xmlns:fwc="http://alx.vingrad.ru/fwc" />');
            foreach($tmp as $v) {
                $opt = $xml->addChild('fwc:option', $v[0]);
                if (!empty($v[1])) {
                    $opt->addAttribute('value', $v[1]);
                }

                if (!empty($v[2])) {
                    foreach($v[2] as $i => $val) {
                        $opt->addAttribute($i, $val);
                    }
                }
            }
        } else {
            if(!file_exists($xml_file)) {
                throw new RuntimeException(sprintf('XML file "%s" doesn\'t exist', $xml_file));
            }
            $xml = simplexml_load_file($xml_file);
        }

        $path = dirname($xml_file).'/';
        $xml->addAttribute('path', $path);

        if(null === $xml['skin'] && (!isset($attributes['skin']) || empty($attributes['skin']))) {
            $xml->addAttribute('skin', (strpos($_SERVER['HTTP_USER_AGENT'],'Opera') === false) ? 'ss_winxp' : 'ss_opera');
        }

        if(null !== $attributes) {
            $json = json_decode($attributes, 1);
            if (is_array($json)) {
                $a = $xml->attributes();
                foreach($json as $i => $v) {
                    if(!empty($a[$i])) {
                        $a[$i] = $v;
                    } else {
                        $xml->addAttribute($i, $v);
                    }
                }
            }
        }
        $attributes = $xml->attributes();

        $xslfile = isset($attributes['design']) ? $path.$attributes['design'].'.xsl' : dirname(__FILE__).'/../design/design.xsl';
        $xslt = new XSLTProcessor();
        $xslt->importStyleSheet($xsl);

        return $xslt->transformToXML($xml);
    }

    /**
     * Class constructor
     *
     * @throws  IllegalStateException , RuntimeException
     */
    private function __construct()
    {
        if (!extension_loaded('SimpleXML')) {
            throw new RuntimeException('SimpleXML extension not loaded');
        }
        if (!extension_loaded('XSL')) {
            throw new RuntimeException('XSL extension not loaded');
        }
    }

    /**
     * Method for object clone.
     * Throws CloneNotSupportedException because of using singleton-pattern in schema
     *
     * @throws  CloneNotSupportedException
     */
    private function __clone()
    {
        throw new CloneNotSupportedException('Singleton should not be cloned');
    }
}
?>